﻿
using System;
using System.Linq;
using System.Reflection;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

using MTP.Core.Remote;

namespace MTP.Core
{

    public class MtpRemoteFactory
    {
        private static readonly MethodInfo method = typeof(MtpRemoteFactory).GetMethod(nameof(CreateInstance), BindingFlags.Static | BindingFlags.NonPublic);


        private static Random _random = new Random();

        private static RemoteOptions GetRemoteOptions(IServiceProvider serviceProvider, string serviceName)
        {
            var options = serviceProvider.GetService<IOptions<MtpOptions>>().Value;
            var remoteOptions = options.RemoteServices.Where(a => a.ServiceNames.Contains(serviceName)).ToArray();
            var index = 0;
            if (remoteOptions.Length > 0)
            {
                if (remoteOptions.Length > 1)
                    index = _random.Next(remoteOptions.Length);
                return remoteOptions[index];
            }
            throw new MissingMethodException("远程服务未启动：" + serviceName);
        }



        private static T CreateInstance<T>(IServiceProvider serviceProvider, string serviceName)
        {
            return ClientDispatchProxy.Proxy<T>(serviceName, () => GetRemoteOptions(serviceProvider, serviceName));
        }


        public static object CreateInstance(IServiceProvider serviceProvider, Type implementationType, object[] attributes)
        {
            if (implementationType.IsInterface)
            {
                if (attributes.Any(a => a is MtpResourceAttribute))
                    return method.MakeGenericMethod(implementationType).Invoke(null, new object[] { serviceProvider, implementationType.Name });
                else if (serviceProvider.GetService<IOptions<MtpOptions>>().Value.RemoteServices.Any(a => a.ServiceNames.Contains(implementationType.Name)))
                    return method.MakeGenericMethod(implementationType).Invoke(null, new object[] { serviceProvider, implementationType.Name });
            }
            return null;
        }



    }
}
